using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using System.Runtime.Serialization;
using Kollektiv.DB;
using Kollektiv.Service;
using Kollektiv.DataModel;
using Kollektiv.Config;
using Kollektiv.Web.Mvc;
using Kollektiv.Extension;
using System.Text;
using System.Reflection;
using System.IO;
using System.Collections.Generic;

namespace Kollektiv.Controller
{
    #region config objects
    [DataContract]
    public class BaseControllerConfig
    {
        [DataMember(Order = 0)]
        public string BaseRouteID { get; set; }

        [DataMember(Order = 1)]
        public string BaseDataServiceID { get; set; }

        [DataMember(Order = 2)]
        public string ResourceDir { get; set; }

        [DataMember(Order = 3)]
        public int SessionInactivityTimeout { get; set; }

        [DataMember(Order = 4)]
        public IEnumerable<ClientConfig> Clients { get; set; }
    }

    [DataContract]
    public class ClientConfig
    {
        [DataMember(Order = 0)]
        public string ID { get; set; }

        [DataMember(Order = 1)]
        public int PingIntervall { get; set; }

        [DataMember(Order = 2)]
        public IEnumerable<ConfigValue> Values { get; set; }
    }
    #endregion

    [Controller]
    public class Base : Kollektiv.Web.Mvc.Controller
    {
        private static BaseControllerConfig config;

        static Base()
        {
            config = ConfigService.Load<BaseControllerConfig>();
            Initialize();
        }

        public static string BaseDataServiceID { get { return config.BaseDataServiceID; } }

        public static int SessionInactivityTimeout { get { return config.SessionInactivityTimeout; } }

        public static DataService BaseDataService { get; private set; }

        public static EmailService EmailService { get; private set; }

        public static Language DefaultLanguage { get; private set; }

        public static string BaseRouteID { get { return config.BaseRouteID; } }

        protected static void Initialize()
        {
            try
            {
                InitializeDataManager();
            }
            catch
            {
            }

            try
            {
                InitializeLanguage();
            }
            catch
            {
            }

            try
            {
                InitializeEmailService();
            }
            catch
            {
            }
        }

        private static void InitializeDataManager()
        {
            if (BaseDataService != null)
                BaseDataService.Dispose();
            BaseDataService = DataService.GetInstance(BaseDataServiceID);
        }

        private static void InitializeLanguage()
        {
            string defaultLanguageISO = BaseDataService.GetRepository<SettingRepository>().All
                .Where(s => s.Type == "Kollektiv.BaseController.DefaultLanguage").FirstOrDefault().Value;
            DefaultLanguage = BaseDataService.GetRepository<LanguageRepository>().All
                    .Where(l => l.ISO == defaultLanguageISO).FirstOrDefault();
        }

        private static void InitializeEmailService()
        {
            string fromAddress = BaseDataService.GetRepository<SettingRepository>().All
                .Where(s => s.Type == "Kollektiv.Service.EmailService.fromAddress").First().Value;
            string smtpHost = BaseDataService.GetRepository<SettingRepository>().All
                .Where(s => s.Type == "Kollektiv.Service.EmailService.smtpHost").First().Value;
            int smtpPort = Convert.ToInt32(BaseDataService.GetRepository<SettingRepository>().All
                .Where(s => s.Type == "Kollektiv.Service.EmailService.smtpPort").First().Value);

            string smtpUsername = null;
            string smtpPassword = null;

            Setting smtpUsernameSetting = BaseDataService.GetRepository<SettingRepository>().All
                .Where(s => s.Type == "Kollektiv.Service.EmailService.smtpUsername").FirstOrDefault();

            if (smtpUsernameSetting != null)
            {
                smtpUsername = smtpUsernameSetting.Value;
                smtpPassword = BaseDataService.GetRepository<SettingRepository>().All
                    .Where(s => s.Type == "Kollektiv.Service.EmailService.smtpPassword").First().Value;
            }

            bool smtpSSL = Convert.ToBoolean(BaseDataService.GetRepository<SettingRepository>().All
                .Where(s => s.Type == "Kollektiv.Service.EmailService.smtpSSL").First().Value);

            EmailService = new EmailService(fromAddress, smtpHost, smtpPort, smtpUsername, smtpPassword, smtpSSL);
        }

        [ControllerAction]
        public ClientConfig GetClientConfig(string profile)
        {
            ClientConfig clientConfig = config.Clients.Where(c => c.ID == profile).FirstOrDefault();

            return clientConfig ?? config.Clients.Where(c => string.IsNullOrEmpty(c.ID)).FirstOrDefault();
        }

        [ControllerAction]
        public FileStreamResult Resource(string assemblyName, string resourceKey, string resourceType)
        {
            Stream s = System.IO.File.OpenRead(Path.Combine(config.ResourceDir, assemblyName, resourceKey));

            return this.File(s, resourceType);
        }

        [ControllerAction]
        public FileStreamResult DynamicResource(string assemblyName, string resourceKey, string resourceType)
        {
            using (Stream s = System.IO.File.OpenRead(Path.Combine(config.ResourceDir, assemblyName, resourceKey)))
            {
                string str = s.AsString();

                return this.File(this.FillVariables(str).GetStream(), resourceType);
            }
        }

        [ControllerAction]
        public FileStreamResult HtmlResource(string assemblyName, string resourceKey)
        {
            return this.DynamicResource(assemblyName, resourceKey, "text/html");
        }

        [ControllerAction]
        public FileStreamResult JavaScriptResource(string assemblyName, string resourceKey)
        {
            return this.DynamicResource(assemblyName, resourceKey, "text/javascript");
        }

        [ControllerAction]
        public FileStreamResult CssResource(string assemblyName, string resourceKey)
        {
            return this.DynamicResource(assemblyName, resourceKey, "text/css");
        }

        protected string FillVariables(string s)
        {
            return s
                .Replace("$(BaseRouteID)", BaseRouteID);
        }

        protected RedirectResult RedirectToRessource(string ressourceKey, string ressourceType)
        {
            return this.RedirectToRessource(this.GetType().Assembly, ressourceKey, ressourceType);
        }

        protected RedirectResult RedirectToRessource(Assembly assembly, string ressourceKey, string ressourceType)
        {
            RouteValueDictionary dict = new RouteValueDictionary();
            dict.Add("assemblyName", assembly.GetName().Name);
            dict.Add("ressourceKey", ressourceKey);
            dict.Add("ressourceType", ressourceType);

            return this.RedirectToAction("Ressource", this.GetType().Name, dict);
        }

        protected new RedirectResult RedirectToAction(string actionName, object routeValues)
        {
            return this.RedirectToAction(actionName, new RouteValueDictionary(routeValues));
        }

        protected new RedirectResult RedirectToAction(string actionName, RouteValueDictionary routeValues)
        {
            return this.RedirectToAction(actionName, this.GetType().Name, routeValues);
        }

        protected new RedirectResult RedirectToAction(string actionName, string controllerName, object routeValues)
        {
            return this.RedirectToAction(actionName, controllerName, new RouteValueDictionary(routeValues));
        }

        protected new RedirectResult RedirectToAction(string actionName, string controllerName, RouteValueDictionary routeValues)
        {
            return this.RedirectToAction(actionName, controllerName, this.RouteID, routeValues);
        }

        protected RedirectResult RedirectToAction(string actionName, string controllerName, string routeid, object routeValues)
        {

            return this.RedirectToAction(actionName, controllerName, routeid, new RouteValueDictionary(routeValues));
        }

        protected RedirectResult RedirectToAction(string actionName, string controllerName, string routeid, RouteValueDictionary routeValues)
        {
            StringBuilder qryb = new StringBuilder();
            foreach (string key in routeValues.Keys)
            {
                if (qryb.ToString() != string.Empty)
                    qryb.Append("&");

                qryb.AppendFormat("{0}={1}", key, routeValues[key].ToString());
            }

            return this.Redirect(string.Format("/{0}/{1}/{2}?{3}", routeid, controllerName, actionName, qryb.ToString()));
        }

        protected RedirectResult RedirectToRoot()
        {
            return this.Redirect("/");
        }

        [ControllerAction]
        public IEnumerable<string> GetRoutes()
        {
            return RouteService.GetInstances().Where(rs=>rs.ID != BaseRouteID).Select(rs => rs.ID);
        }
    }
}

